as.directive('aPreloader', preloader);

preloader.$inject = [
    '$animate',
    '$timeout',
    '$q'
];
function preloader($animate, $timeout, $q) {

    var directive = {
        restrict: 'EAC',
        template: '<div class="preloader-progress bounceIn animated">' + '<div class="preloader-progress-bar" ' + 'ng-style="{width: loadCounter + \'%\'}"></div>' + '</div>',
        link: link
    };
    return directive;

    // /////

    function link(scope, el) {
        scope.loadCounter = 0;

        var counter = 0, timeout;

        // disables scrollbar
        angular.element('body').css('overflow', 'hidden');
        // ensure class is present for styling
        el.addClass('preloader');

        appReady().then(endCounter);

        timeout = $timeout(startCounter);

        // /////

        function startCounter() {

            var remaining = 100 - counter;
            counter = counter + (0.015 * Math.pow(1 - Math.sqrt(remaining), 2));

            scope.loadCounter = parseInt(counter, 10);

            timeout = $timeout(startCounter, 20);
        }

        function endCounter() {

            $timeout.cancel(timeout);

            scope.loadCounter = 100;

            $timeout(function () {
                // animate preloader hiding
                $animate.addClass(el, 'preloader-hidden');
                // retore scrollbar
                angular.element('body').css('overflow', '');
            }, 300);
        }

        function appReady() {
            var deferred = $q.defer();
            var viewsLoaded = 0;
            // if this doesn't sync with the real app ready
            // a custom event must be used instead
            var off = scope.$on('$viewContentLoaded', function () {
                viewsLoaded++;
                // we know there are at least two views to be loaded
                // before the app is ready (1-index.html 2-app*.html)
                if (viewsLoaded === 2) {
                    // with resolve this fires only once
                    $timeout(function () {
                        deferred.resolve();
                    }, 3000);

                    off();
                }

            });

            return deferred.promise;
        }

    } // link
}